﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CommonLib;
using MindFusion.Diagramming;
namespace Constructor
{
    [Serializable]
    public partial class Frame : Object, ICloneable
    {
        private FrameType _type;
        public string Name { get; set; }
        public string ID { get; set; }
        public FrameType Type { get { return _type; } set { _type = value; } }
        public TableNode Node { get; set; }
        public TreeNode TreeNode { get; set; }
        public FieldItem FieldItem { get; set; }
        public int Priority { get; set; }
        public Frame()
        {
        }

        public Frame(string name, FrameType type)
        {
            Name = name;
            Type = type;
            Priority = 0;
            ID = Guid.NewGuid().ToString();
        }
        public Frame(string name, FrameType type, string id)
        {
            Name = name;
            Type = type;
            Priority = 0;
            ID = id;
        }
        public Frame(string name)
        {
            Name = name;
            Type = Properties.Settings.Default.defaultFrameType;
            Slots = new List<Slot>();
            Priority = 0;
            ID = Guid.NewGuid().ToString();
        }

        /// <summary>
        /// Возвращает родительский фрейм.
        /// </summary>
        public Frame ParentFrame
        {
            get
            {
                foreach (Slot c in Slots)
                    if (c.Type == CommonLib.SlotType.AKO)
                        return c.Subframe;
                return null;
            }
        }

        /// <summary>
        /// Возвращает слоты, определенные данным фреймом.
        /// </summary>
        public List<Slot> Slots
        {
            get;
            set;
        }

        /// <summary>
        /// Возвращает все слоты, включая родительские.
        /// </summary>
        public List<Slot> AllSlots
        {
            get
            {
                List<Slot> result = new List<Slot>();
                result.AddRange(Slots);
                if (ParentFrame != null)
                {
                    foreach (Slot slot in ParentFrame.AllSlots)
                    {
                        if ((slot.Type == SlotType.Regular || slot.Type == SlotType.Production || slot.Type == SlotType.SubFrame)
                            && result.Find(o => o.Name == slot.Name) == null)
                            result.Add(slot);
                    }
                }
                return result;
            }
        }
        public List<Slot> OnlyOwnSlots
        {
            get
            {
                List<Slot> result = new List<Slot>();
                if (ParentFrame != null)
                {
                    foreach (Slot slot in Slots)
                        if (slot.Type == SlotType.Regular || slot.Type == SlotType.Production || slot.Type == SlotType.SubFrame)
                        {
                            if (ParentSlots.Find(o => o.Name == slot.Name) == null)
                                result.Add(slot);
                        }
                        else
                            result.Add(slot);
                    return result;
                }
                else
                    return Slots;
            }
        }
        public List<Slot> ParentSlots
        {
            get
            {
                List<Slot> result = new List<Slot>();
                if (ParentFrame != null)
                {
                    foreach (Slot slot in ParentFrame.AllSlots)
                    {
                        if ((slot.Type == SlotType.Regular || slot.Type == SlotType.Production || slot.Type == SlotType.SubFrame)
                            && result.Find(o => o.Name == slot.Name) == null)
                        {
                            Slot temp = Slots.Find(o => o.Name == slot.Name);
                            if (temp == null)
                            {
                                Slot s = slot.Clone(this);
                                s.isOwn = false;
                                result.Add(s);
                            }
                            else
                                result.Add(temp);
                        }
                    }
                }
                return result;
            }
        }
        public void MoveSlot(Slot s, int new_pos)
        {
            if (Slots.Contains(s) && s.isOwn)
            {
                int old_pos = Slots.IndexOf(s);
                new_pos = old_pos + new_pos;
                Slots.RemoveAt(old_pos);
                if (new_pos < 0) new_pos = 0;
                Slots.Insert(Math.Min(new_pos, Slots.Count), s);
            }
        }
        public List<Slot> GetSlotsForProductions()
        {
            List<Slot> result = new List<Slot>();
            result.AddRange(Slots);
            if (ParentFrame != null)
            {
                int ind = 0;
                foreach (Slot slot in ParentFrame.GetSlotsForProductions())
                {
                    if ((slot.Type == SlotType.Regular || slot.Type == SlotType.Production || slot.Type == SlotType.SubFrame)
                        && result.Find(o => o.Name == slot.Name) == null)
                    {
                        result.Insert(ind, slot);
                        ind++;
                    }
                }
            }
            return result;
        }
        public List<Slot> MLOAllSlots
        {
            get
            {
                List<Slot> result = new List<Slot>();
                result.AddRange(Slots);
                if (ParentFrame != null)
                {
                    foreach (Slot slot in ParentFrame.AllSlots)
                    {
                        if (slot.Type == SlotType.Regular || slot.Type == SlotType.Production || slot.Type == SlotType.SubFrame
                            && result.Find(o => o.Name == slot.Name) == null)
                            result.Add(slot.Clone(this));
                    }
                }
                return result;
            }
        }
        public Slot SearchSlot(string name)
        {
            return Slots.Find(o => o.Name == name);
        }
        public Slot SearchInAllSlot(string id)
        {
            //return AllSlots.Find(o => o.Name == name);
            foreach (Slot s in AllSlots)
                if (s.Name == id || s.ID == id) return s;
            return null;
        }
        public Slot SearchInOwnSlot(string name)
        {
            //return AllSlots.Find(o => o.Name == name);
            foreach (Slot s in OnlyOwnSlots)
                if (s.Name == name) return s;
            return null;
        }
        public string GetSlotName()
        {
            int i = 0;
            while (true)
            {
                if (SearchInAllSlot("Slot" + i.ToString()) == null) break;
                i++;
            }
            return "Slot" + i.ToString();
        }
        private void add_slot_Click(object sender, EventArgs e)
        {
            Slot slot = new Slot(this);
            slot.Name = GetSlotName();
            Slots.Add(slot);
        }
        public void SaveInDataSet(DataSet ds)
        {
            DataTable dt = ds.Tables["Frames"];
            DataRow row = dt.NewRow();
            row["name"] = Name;
            row["type"] = Type.ToString();
            row["priority"] = Priority.ToString();
            row["id"] = ID;
            if (Type == FrameType.Exemplar && External.Parents.ContainsKey(this.ID))
                row["prototype"] = External.Parents[this.ID].ID;
            dt.Rows.Add(row);
            foreach (Slot slot in Slots)
                slot.SaveInDataSet(ds);
        }
        public void RepaintNode(bool refresh_treeview)
        {
            if (Node == null) return;
            Node.Caption = Name;
            Node.RowCount = 1 + Slots.Count();
            Node.ColumnCount = 2;
            Node[0, 0].Text = "Тип";
            switch (Type)
            {
                case CommonLib.FrameType.Prototype:
                    Node[1, 0].Text = "Прототип";
                    break;
                case CommonLib.FrameType.Situation:
                    Node[1, 0].Text = "Ситуация";
                    break;
                case CommonLib.FrameType.Exemplar:
                    Node[1, 0].Text = "Экземпляр";
                    break;
            }
            int i = 1;
            foreach (Slot slot in Slots)
            {
                Node[0, i].Text = slot.Name;
                switch (slot.Type)
                {
                    case SlotType.AKO:
                        if (slot.Subframe != null)
                            Node[1, i].Text = slot.Subframe.Name;
                        break;
                    case SlotType.Production:
                        try
                        {
                            if (slot.Production != null)
                                if (!slot.Production.isProc)
                                    Node[1, i].Text = slot.Production.Item.Text + slot.Production.Operation + slot.Production.Value;
                                else
                                    Node[1, i].Text = slot.Production.Procedure.Text;
                        }
                        catch { }
                        break;
                    case SlotType.Regular:
                        switch (slot.Domain.Type)
                        {
                            case DomainType.Enum:
                                if (slot.Default != null)
                                    Node[1, i].Text = slot.Default.ToString();
                                break;
                            case DomainType.Number:
                                if (slot.Default != null)
                                    Node[1, i].Text = slot.Default.ToString();
                                break;
                            case DomainType.Image:
                                if (slot.Default != null)
                                    if (External.images.LoadedImages != null && External.images.LoadedImages.ContainsKey(slot.Default.ToString()))
                                        Node[1, i].Image = External.images.LoadedImages[slot.Default.ToString()].BackgroundImage;
                                break;
                        }
                        break;
                    case SlotType.SubFrame:
                        if (slot.Subframe != null)
                            Node[1, i].Text = slot.Subframe.Name;
                        break;
                }
                i++;
            }
            //if (refresh_treeview)
            //    External.explorer.Fill();
            FillTreeNode(TreeNode);
            External.constructor.DrawLinks();
        }

        public void slot_Change(object sender, EventArgs e)
        {
            Change();
        }
        public void RepaintFieldItem()
        {
            if (FieldItem != null)
            {
                FieldItem.Init(this);
            }
        }
        public void Change()
        {
            if (FieldItem != null)
            {
                RepaintFieldItem();
                bool boo=true;
                if (FieldItem.Parent as TableLayoutPanel != null)
                {
                    var i1 = (FieldItem.Parent as TableLayoutPanel).GetCellPosition(FieldItem);
                    var i2 = External.exemplars.field.GetCoordByCell(this.GetPositionSlot().Subframe);
                    boo=i1.Column == i2.y && i1.Row == i2.x;
                }
                if (GetPositionSlot() != null && !boo)
                    FieldItem.Move(this.GetPositionSlot().Subframe);
            }
        }
        public void FillTreeNode(TreeNode node)
        {
            if (node != null)
            {
                node.Nodes.Clear();
                foreach (Slot s in Slots)
                {
                    TreeNode s_node = node.Nodes.Add(s.Name);
                    s_node.Tag = s;
                }
                node.Text = Name;
                External.explorer.ChangeGroup(TreeNode);
            }
        }
        public object Clone()
        {
            Frame f = new Frame(Name);
            f.Node = Node;
            f.TreeNode = TreeNode;
            f.Priority = Priority;
            f.ID = ID;
            foreach (Slot slot in Slots)
            {
                f.Slots.Add(slot.Clone(f));
            }
            f.Type = Type;
            return f;
        }
        public override string ToString()
        {
            return Name;
        }
        public bool isUsedDomain(string name)
        {
            foreach (Slot slot in Slots)
                if (slot.isUsedDomain(name)) return true;
            return false;
        }
        public bool ContainsAKOSlot()
        {
            foreach (Slot slot in Slots)
                if (slot.Type == SlotType.AKO) return true;
            return false;
        }
        public bool ContainsNextSlot()
        {
            foreach (Slot slot in Slots)
                if (slot.Type == SlotType.Next) return true;
            return false;
        }
        public bool ContainsErrorSlot()
        {
            foreach (Slot slot in Slots)
                if (slot.Type == SlotType.Error) return true;
            return false;
        }
        public bool ContainsSubframe(string subframe)
        {
            foreach (Slot slot in AllSlots)
                if (slot.Type == SlotType.SubFrame && slot.Subframe.Name == subframe) return true;
            return false;
        }
        public bool ContainsAKOFrame(string subframe)
        {
            foreach (Slot slot in AllSlots)
                if (slot.Type == SlotType.AKO && slot.Subframe.Name == subframe) return true;
            return false;
        }
        public Slot GetImageSlot()
        {
            foreach (Slot slot in AllSlots)
                if (slot.Type == SlotType.Regular && slot.DomainID == "Images") return slot;
            return null;
        }
        public bool ContainsImageSlot()
        {
            return GetImageSlot() != null;
        }
        //public Slot GetCellSlot()
        //{
        //    foreach (Slot slot in AllSlots)
        //        if (slot.Type == SlotType.SubFrame && slot.Subframe != null && slot.Subframe.Type == FrameType.Prototype && slot.Subframe.Name == "Клетка")
        //            return slot;
        //        else
        //            if (slot.Type == SlotType.SubFrame && slot.Subframe != null
        //                && slot.Subframe.Type == FrameType.Exemplar
        //                && External.Parents.ContainsKey(slot.Subframe) && External.Parents[slot.Subframe].Name == "Клетка") return slot;

        //    return null;
        //}
        public Slot GetPositionSlot()
        {
            foreach (Slot slot in AllSlots)
                if (slot.Type == SlotType.SubFrame && slot.Subframe != null && slot.Subframe.Type == FrameType.Prototype && slot.Subframe.Name == "Клетка" && slot.Name == "Позиция")
                    return slot;
                else
                    if (slot.Type == SlotType.SubFrame && slot.Subframe != null
                        && slot.Subframe.Type == FrameType.Exemplar
                        && External.Parents.ContainsKey(slot.Subframe.ID) && External.Parents[slot.Subframe.ID].Name == "Клетка" && slot.Name == "Позиция") return slot;

            return null;
        }
        public List<Slot> GetSlots(bool all)
        {
            if (all)
                return AllSlots;
            else
                return Slots;
        }
        public List<Slot> GetSlots(Frame Prototype)
        {
            return GetSlots(SlotType.SubFrame, true).FindAll(o => o.Subframe != null && External.Parents.ContainsKey(o.Subframe.ID) && External.Parents[o.Subframe.ID].Name == Prototype.Name);
        }
        public List<Slot> GetSlots(SlotType st, bool all)
        {
            if (all)
                return AllSlots.FindAll(o => o.Type == st);
            else
                return Slots.FindAll(o => o.Type == st);
        }
    }
}
